﻿using System;
using System.Security.Permissions;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using AdTech.Common;
using AdTech.Snap.Interop;

namespace AdTech.Snap
{
    #pragma warning disable 1591
    public abstract class GlassViewModel : ViewModelBase
    {
        // Fields
        private bool wmHookSetup;
        private IntPtr windowHandle;
        protected bool _IsAeroGlassEnabled;
        protected Thickness _GlassFrameMargin;

        // Properties
        public Thickness GlassFrameMargin
        {
            get { return _GlassFrameMargin; }
            set { _GlassFrameMargin = value; }
        }
        public bool IsAeroGlassEnabled
        {
            get { return _IsAeroGlassEnabled; }
            set { _IsAeroGlassEnabled = value; NotifyPropertyChanged(() => this.IsAeroGlassEnabled); }
        }

        // Constructor
        public GlassViewModel()
        {
        }

        // Methods
        [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
        protected void ExtendWindowFrame(IntPtr hWnd, Thickness margin)
        {
            this.windowHandle = hWnd;
            this.GlassFrameMargin = margin;
            this.IsAeroGlassEnabled = GetIsAeroGlassEnabled();

            if (this.IsAeroGlassEnabled)
            {
                HwndSource mainWindowSrc = HwndSource.FromHwnd(hWnd);
                mainWindowSrc.CompositionTarget.BackgroundColor = Color.FromArgb(0, 0, 0, 0);

                // Get System Dpi
                //System.Drawing.Graphics desktop = System.Drawing.Graphics.FromHwnd(mainWindowPtr);
                float dpi = 96;

                // Extend glass frame into client area
                // Note that the default desktop Dpi is 96dpi. The  margins are
                // adjusted for the system Dpi.
                this._GlassFrameMargin.Left = Convert.ToInt32(this.GlassFrameMargin.Left * (dpi / 96));
                this._GlassFrameMargin.Right = Convert.ToInt32(this.GlassFrameMargin.Right * (dpi / 96));
                this._GlassFrameMargin.Top = Convert.ToInt32(this.GlassFrameMargin.Top * (dpi / 96));
                this._GlassFrameMargin.Bottom = Convert.ToInt32((this.GlassFrameMargin.Bottom) * (dpi / 96));

                MARGINS margins = this.GlassFrameMargin;
                NativeMethods.DwmExtendFrameIntoClientArea(mainWindowSrc.Handle, ref margins);
            }

            if (!wmHookSetup)
            {
                // Listen to Enable/Disable of Aero Theme
                HwndSource.FromHwnd(hWnd).AddHook(new HwndSourceHook(WindowProc));
                wmHookSetup = true;
            }
        }

        [System.Diagnostics.DebuggerStepThrough]
        [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
        protected IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            switch ((WM)msg)
            {
                case WM.DWMCOMPOSITIONCHANGED:
                    ExtendWindowFrame(this.windowHandle, this.GlassFrameMargin);
                    break;
            }
            return IntPtr.Zero;
        }
        
        protected bool GetIsAeroGlassEnabled()
        {
            if (Environment.OSVersion.Version.Major < 6)
                return false;

            bool result;
            NativeMethods.DwmIsCompositionEnabled(out result);
            return result;
        }

        #region IDisposable Members
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        // The bulk of the clean-up code is implemented in Dispose(bool)
        /// <summary>
        /// <remarks>http://msdn.microsoft.com/en-us/library/ms244737.aspx</remarks>
        /// </summary>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (wmHookSetup)
                    HwndSource.FromHwnd(windowHandle).RemoveHook(new HwndSourceHook(WindowProc));
            }
        }
        #endregion
    }
    #pragma warning restore 1591
}
